package top.xzxsrq.fileviewutils.plugin;

import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import top.xzxsrq.common.utils.FileUtilsZX;
import top.xzxsrq.common.utils.StringUtilsZX;
import top.xzxsrq.fileviewutils.FileViewUtilsApplication;
import top.xzxsrq.utils.PathUtils;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

@Component
@Log4j2
public class WatchDir extends FileAlterationListenerAdaptor implements ApplicationRunner {

    @Autowired
    private SpringDynamicLoadJar springDynamicLoadJar;
    public List<String> pagePlugins = new CopyOnWriteArrayList<>();
    private final String pluginPath = FileViewUtilsApplication.projectDir + "/plugin/";
    private final String staticPageDir = FileViewUtilsApplication.projectDir + "/static";
    private final String staticPagePluginDir = staticPageDir + "/pagePlugin";
    private final String staticJarPluginDir = staticPageDir + "/jarPlugin";

    public void init() {
        FileUtilsZX.createDir(pluginPath);
        // 创建监视器
        FileAlterationMonitor monitor = new FileAlterationMonitor(500);
        FileAlterationObserver observer = new FileAlterationObserver(pluginPath);
        observer.addListener(this);
        monitor.addObserver(observer);
        try {
            monitor.start();
            log.info("{}：文件夹开始监听", pluginPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
        this.initPlugin();
    }

    private void initPlugin() {
        log.info("开始初始化插件");
        FileUtilsZX.deleteDirectory(staticPagePluginDir);
        FileUtilsZX.deleteDirectory(staticJarPluginDir);
        File file = new File(pluginPath);
        File[] files = file.listFiles();
        if (files == null || files.length == 0) {
            log.warn("插件文件夹里面没有插件");
            return;
        }
        List<File> collect = Arrays
                .stream(files)
                .filter(File::isDirectory)
                .collect(Collectors.toList());
        for (File dir : collect) {
            String dirName = dir.getName();
            // 获取到jar
            String jarFilePath = dir.getAbsolutePath() + "/" + dirName + ".jar";
            // 获取到页面插件文件夹
            String staticDirPath = dir.getAbsolutePath() + "/static";
            // 加载jar
            if (FileUtilsZX.exists(new File(jarFilePath))) {
                log.info("检索到后台插件：{}", dirName);
                addJarToApp(dirName, jarFilePath);
            }
            // 加载页面
            if (FileUtilsZX.exists(new File(staticDirPath))) {
                log.info("检索到页面插件：{}", dirName);
                String copyTo = staticPagePluginDir + "/" + dirName;
                try {
                    FileUtilsZX.copyDirectory(new File(staticDirPath), new File(copyTo));
                    log.info("文件夹复制完成：{}", staticDirPath);
                    String path = "./pagePlugin/" + dirName + "/main.js";
                    pagePlugins.add(path);
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("文件夹：{}：复制错误", staticDirPath);
                }
            }
        }
    }

    private String getFileNameByPluginPath(String filePath) {
        String replace = filePath.replace(pluginPath, "");
        String[] split = replace.split("/");
        for (String s : split) {
            if (s.length() != 0) {
                log.info("解析到的插件名称：{}", s);
                return s;
            }
        }
        log.error("插件名称获取错误");
        return "";
    }

    private void deleteFileWatcher(String filePath) {
        String pluginName = this.getFileNameByPluginPath(filePath);
        if (StringUtilsZX.isEmpty(pluginName)) {
            return;
        }
        if (filePath.endsWith(".jar")) {
            if ((pluginPath + pluginName + "/" + pluginName + ".jar").equals(filePath)) {
                log.info("卸载后台插件：{}--------开始", pluginName);
                String jarPluginFilePath = staticJarPluginDir + "/" + pluginName + ".jar";
                boolean b = springDynamicLoadJar.unloadJar(jarPluginFilePath);
                if (b) {
                    FileUtilsZX.deleteFile(jarPluginFilePath);
                    log.info("卸载后台插件：{}--------完成", pluginName);
                }
            }
        } else {
            String s = pluginPath + pluginName + "/static";
            if (PathUtils.isChildPath(filePath, s)) {
                log.info("卸载前端文件--------开始");
                String replace = filePath.replace(s, staticPagePluginDir + "/" + pluginName);
                if ((s + "/main.js").equals(filePath)) {
                    String path = "./pagePlugin/" + pluginName + "/main.js";
                    pagePlugins.remove(path);
                    log.info("移除前端插件：{}--------开始", pluginName);
                }
                FileUtilsZX.deleteFile(replace);
                log.info("卸载前端文件--------完成");
            }
        }
    }

    private void updateFileWatcher(String filePath) {
        deleteFileWatcher(filePath);
        createFileWatcher(filePath);
    }

    private void addJarToApp(String pluginName, String filePath) {
        try {
            FileUtilsZX.copyFileToDirectory(new File(filePath), new File(staticJarPluginDir));
            springDynamicLoadJar.loadJar(staticJarPluginDir + "/" + pluginName + ".jar");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void createFileWatcher(String filePath) {
        String pluginName = this.getFileNameByPluginPath(filePath);
        if (StringUtilsZX.isEmpty(pluginName)) {
            return;
        }
        if (filePath.endsWith(".jar")) {
            if ((pluginPath + pluginName + "/" + pluginName + ".jar").equals(filePath)) {
                log.info("监听到新的后台插件：{}", pluginName);
                addJarToApp(pluginName, filePath);
            }
        } else {
            String s = pluginPath + pluginName + "/static";
            if (PathUtils.isChildPath(filePath, s)) {
                log.info("创建前端文件--------开始");
                String replace = filePath.replace(s, staticPagePluginDir + "/" + pluginName);
                if ((s + "/main.js").equals(filePath)) {
                    String path = "./pagePlugin/" + pluginName + "/main.js";
                    pagePlugins.add(path);
                    log.info("添加前端插件：{}--------开始", pluginName);
                }
                try {
                    FileUtilsZX.copyFile(new File(filePath), new File(replace));
                    log.info("创建前端文件--------完成");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void onFileCreate(File file) {
        this.createFileWatcher(PathUtils.getCanonicalPath(file));
    }

    @Override
    public void onFileChange(File file) {
        this.updateFileWatcher(PathUtils.getCanonicalPath(file));
    }

    @Override
    public void onFileDelete(File file) {
        this.deleteFileWatcher(PathUtils.getCanonicalPath(file));
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        this.init();
    }
}
